/*
 * JVM_Thread.c
 *
 *  Created on: 03.01.2011
 *      Author: Tavin
 */
#include <stdlib.h>

#include "boolean.h"

#include "JVM_StatusCodes.h"
#include "JVM_Class.h"
#include "JVM_Method.h"

#include "JVM_Thread.h"
#include "JVM_StackFrame.h"
#include "JVM_Opcode.h"

#include "MainTimer.h"

/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_add								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/


void JVM_Thread_init()
{
	threadList=NULL;
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_StackFrame_new							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.3			Status : Working   			*/
/*																						*/
/****************************************************************************************/


JVM_Thread_t * JVM_Thread_newThread(JVM_Class_t *myClass, JVM_Method_t *myMethod)
{
	JVM_StackFrame_t * myStackFrame;
	JVM_Thread_t * myThread;

	myStackFrame=JVM_StackFrame_new(myClass->constantPoolTable,myMethod);

	//TODO if stackframe==NULL!!!!

	myThread=malloc(sizeof(JVM_Thread_t));


	myThread->status=THREAD_STATUS_NEW;
	myThread->priority=5;
	myThread->currentStackframe=myStackFrame;
	myThread->sleepCounter=0;

	JVM_Thread_add(myThread);
	//myThread

	return(myThread);
}



/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_add								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/


void JVM_Thread_add(JVM_Thread_t *myThread)
{
	JVM_Thread_t *tmpThread;

	if (threadList==NULL)
		{
		threadList=myThread;
		myThread->next=NULL;
		activeThread=myThread;
		}
		else
			{
			tmpThread=threadList;
			while (tmpThread->next!=NULL)
				{
				tmpThread=(JVM_Thread_t *)tmpThread->next;
				}
			tmpThread->next=myThread;
			}
	myThread->next=NULL;

}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_killThread						Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.2.14			Status : Working   			*/
/*																						*/
/****************************************************************************************/


void JVM_Thread_killThread(JVM_Thread_t * threadToKill)
{

	free(threadToKill);

}


/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_remove							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/


uint16_t  JVM_Thread_remove(JVM_Thread_t *myThread)
{
	JVM_Thread_t *tmpThread;

	if (threadList==NULL)
		return(STCD_THREAD_NOT_IN_LIST);



		if ((threadList->next==NULL))
			{
			threadList=NULL;
			return(STCD_OK);
			}

		tmpThread=threadList;

		while (tmpThread->next!=myThread)
			{
			tmpThread=tmpThread->next;
			}
		tmpThread->next=myThread->next;

		return(STCD_OK);
}


/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_switchNext						Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.30			Status : Working   			*/
/*																						*/
/****************************************************************************************/
void JVM_Thread_countDownSleep()
{
	JVM_Thread_t *tmpThread;

	tmpThread=threadList;

	while (tmpThread!=NULL)
		{
		if (tmpThread->sleepCounter!=0)
			{

			tmpThread->sleepCounter--;
			if (tmpThread->sleepCounter==0)
				{
				JVM_Thread_setWaiting(tmpThread);
				}

			}
		tmpThread=tmpThread->next;

		}

}
/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_switchNext						Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.30			Status : Working   			*/
/*																						*/
/****************************************************************************************/
boolean JVM_Thread_switchNext()
{
	JVM_Thread_t * tmpThread;

	tmpThread = activeThread;

	tmpThread=JVM_Thread_getNext(tmpThread);

	while (tmpThread!=activeThread)
	{

		if (JVM_Thread_isWaiting(tmpThread)==TRUE)
			{
			if (JVM_Thread_isRunning(activeThread)==TRUE)
				{
				JVM_Thread_setWaiting(activeThread);
				}

			activeThread=tmpThread;
			JVM_Opcode_setActiveStackFrame(activeThread->currentStackframe);
			JVM_Thread_setRunning(activeThread);
			return(TRUE);
			}
		tmpThread=JVM_Thread_getNext(tmpThread);
	}

return(FALSE);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_executeClassInitThread			Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.2.14			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_Thread_executeClassInitThread()
{
		uint16_t statusCode;

		JVM_Opcode_setActiveStackFrame(activeThread->currentStackframe);

		do {
		statusCode=JVM_Opcode_execute();
		} while (statusCode==STCD_OK);


	return(STCD_OK);
}


/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_executeActiveThread				Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/
/*
uint16_t JVM_Thread_executeActiveThread()
{
	JVM_Opcode_setActiveStackFrame(activeThread->currentStackframe);
	uint16_t statusCode;

	boolean allreadySwitched;

	allreadySwitched=FALSE;

	boolean switchedTask;

	// Try switch to next task
	switchedTask=JVM_Thread_switchNext();

	// if task could not be switched.
	if (JVM_Thread_isRunning(activeThread) == FALSE)
		{

		}


	while(MainTimer_isTick()==FALSE)
		{
		statusCode=JVM_Opcode_execute();

		if (JVM_Thread_isRunning(activeThread) == FALSE)
			{
			allreadySwitched=TRUE;
			JVM_Thread_switchNext();
			}
		}

	if (allreadySwitched==FALSE)
		{
		JVM_Thread_switchNext();
		}

	return(STCD_OK);
}
*/

uint16_t JVM_Thread_executeActiveThread() {
	JVM_Opcode_setActiveStackFrame(activeThread->currentStackframe);
	uint16_t statusCode;

	boolean allreadySwitched;

	allreadySwitched = FALSE;

	while (MainTimer_isTick() == FALSE) {
		statusCode = JVM_Opcode_execute();

		if (statusCode == STCD_THREAD_DESTROY) {
			JVM_Thread_killThread(activeThread);
			JVM_Thread_switchNext();
			return (STCD_OK);
		}

		if (JVM_Thread_isRunning(activeThread) == FALSE) {
			allreadySwitched = TRUE;
			JVM_Thread_switchNext();
		}
	}

	if (allreadySwitched == FALSE) {
		JVM_Thread_switchNext();
	}

	return (STCD_OK);
}


/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_getActiveThread					Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/

JVM_Thread_t * JVM_Thread_getActiveThread()
{
	return(activeThread);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_Thread_sleep								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.30			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_Thread_sleep()
{
	long milis;

	milis=JVM_Opcode_popLongValue();

	if (milis==0)
		return(STCD_OK);

	activeThread->sleepCounter=milis;
	JVM_Thread_setStatus(activeThread,THREAD_STATUS_TIMED_WAITING);

	return(STCD_THREAD_SLEEP);
}
